Dijkstra算法讲解(单源最短路径问题求解)

无论是算法分析课程还是Java课程设计,都对有向图中的最短路径情有独钟,今天准备对单愿最短路径的解决方案进行一下详解,免得每一次用到都是从头再来2333

适用条件:

在有向图中,求一个顶点到其他顶点的最短路径

首先让我们先回顾一下,最简单的多源最短路径的求法:Floyd算法

实例讲解

这里呢我们通过这个例题对这个算法进行解析:(节选自《啊哈算法》)

题目中的关系如图所示:

这里写图片描述

这里呢,我们依旧使用二维数组来存储顶点之间边的关系

这里写图片描述

为了让最后单源路径最短的问题方便读取答案,创建一个1号顶点到其他顶点初始路程的数组dist

这里写图片描述

求解思路

1、首先从距离起点最近的点进行操作,因为起点1不可能通过其他顶点获得到达该最近点的最短路径。
2、那么我们找到了顶点2,和Floyd方法类似,这个时候我们开始经过顶点2对顶点1的其他边进行优化。
3、比较dist[3]与dist[2]+e[2][3]的大小关系,如果dist[3]较大,则进行更新,这就使得顶点1到3的最短路径变短。
4、接下来,再剩下的3,4,5和6号顶点中,继续寻找离1号起点最近的顶点,进行路径更新。
5、最终通过其他顶点的优化后的道德单源最短路径为:
这里写图片描述

总结算法:

1、通过book[i]是否为1判断点i是否已经是最短路径的顶点集合P中,否则在Q中。
2、在Q中选取一个离起点最近的顶点加入到集合P中,并考察所有的以点u为起点的边
3、重复第二步,直到Q为空

算法实现:

/*
 *C语言实现,最简
 */
#include <stdio.h>
int main()
{
    int e[10][10],dis[10],book[10],i,j,n,m,t1,t2,t3,u,v,min;
    int inf = 99999999;//用inf(infinity的缩写)存储一个我们认为的正无穷值
    //读入n和m,n表示顶点个数,m表示边的条数
    scanf("%d %d",&n,&m);
    //初始化
    for(i = 1;i <= n;i++) {
        for(j = 1;j <= n;j++){
            if(i == j) e[i][j] = 0;
            else e[i][j] = inf;
        }
    }
    //读入边
    for (int i = 0; i < m; i++)
    {
        scanf("%d %d %d",&t1,&t2,&t3);
        e[t1][t2] = t3;
    }
    //初始化dis数组
    for(i = 1;i <= n;i++) {
        dis[i] = e[1][i];
    }
    //book数组初始化
    for(i = 1;i <= n;i++)
        book[i] = 0;
    book[1] = 1;

    //Dijkstra算法核心语句
    for(i = 1;i <= n - 1;i++)
    {
        //找到离1号顶点最近的顶点
        min = inf;
        for(j = 1;j <= n;i++)
        {
            if(book[j] == 0 && dis[j] < min)
            {
                min = dis[j];
                u = j;
            }
        }
        book[u] = 1;
        for(v = 1;v <= n;v++)
        {
            if(e[u][v] < inf){
                if(dis[v] > dis[u] + e[u][v])
                    dis[v] = dis[u] + e[u][v];
            }
        }
    }
    //输出最终结果
    for(i = 1;i <= n;i++)
        prntf("%d ",dis[i]);
    getchar();
    getchar();
    return 0;
}
/*
 *Java实现,非最优化解
 */
package com.stortest.path;
import java.util.ArrayList;
import java.util.Scanner;

public class Dijkstra {

    public long[] result;//定义全局变量存储到各点的最短路径

    public class Edge{
        public int a,b,c;
        Edge(int a,int b,int c){//声明构造函数
            this.a = a;
            this.b = b;
            this.c = c;
        }
    }

    public boolean get(int n, int s, Edge[] A) {
        ArrayList<Integer> list = new ArrayList<Integer>();//生成list列表
        //初始化
        result = new long[n];
        boolean[] used = new boolean[n];//存储访问状态
        int[] num = new int[n];
        for(int i = 0;i < n;i++) {
            result[i] = Integer.MAX_VALUE;
            used[i] = false;
        }
        result[s] = 0;     //第s个顶点到自身距离为0
        used[s] = true;    //表示第s个顶点进入数组队
        list.add(s);      //第s个顶点入队


        while(list.size() != 0) {
            int a = list.get(0);   //获取数组队中第一个元素
            list.remove(0);         //删除数组队中第一个元素
            for(int i = 0;i < A.length;i++) {
                //当list数组队的第一个元素等于边A[i]的起点时
                if(a == A[i].a && result[A[i].b] > result[A[i].a] + A[i].c) { 
                    //判断 起点到终点的最短路径 是否可以更新
                    result[A[i].b] = result[A[i].a] + A[i].c;
                    if(!used[A[i].b]) {//如果终点是第一次被遍历
                        list.add(A[i].b);
                        used[A[i].b] = true;   //表示边A[i]的终点b已进入数组队
                    }
                }
            }
           // used[a] = false;        //顶点a出数组对
        }
        return true;
    }

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Dijkstra text = new Dijkstra();//创建对象
        Scanner input = new Scanner(System.in);
        int n = input.nextInt();
        int m = input.nextInt();
        Edge[] A = new Edge[m];//创建内部类对象数组,存储边的关系
        for(int i = 0;i < m;i++)
        {
            int a = input.nextInt() - 1;
            int b = input.nextInt() - 1;
            int c = input.nextInt();
            A[i] = text.new Edge(a,b,c);
        }//接收输入数据
        if(text.get(n,0,A)){//调用子函数,输出到最远点的结果
            System.out.println(text.result[text.result.length - 1]);
        }
}

}

改进:

该算法的时间复杂度为O(N2),对于边数M少于N2的稀疏图来说,可以使用邻接矩阵进行优化,可以使时间复杂度优化到(M+N)logN

  • 6
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值